package br.com.ep.generico.core;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;

import javax.persistence.Embeddable;
import javax.persistence.Entity;

import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.util.ClassUtils;

/**
* ###############################
* @since 23/04/2008
* @version 1.0
* @category Infrastructure
*/
public class AnnotationSessionFactoryBean extends org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean
{
   /*-------------------------------------------------------------------
    *                       ATTRIBUTES
    *-------------------------------------------------------------------*/
   private List<String[]> basePackages;

   private List<String[]> baseEntities;
	   
   private ClassLoader beanClassLoader;
   
   

   /*-------------------------------------------------------------------
    *                        BEHAVIORS
    *-------------------------------------------------------------------*/
   @Override
   public void afterPropertiesSet() throws Exception
   {
	   
	  
      Collection<Class<?>> entities = new ArrayList<Class<?>>();
      ClassPathScanningCandidateComponentProvider scanner = this.createScanner();
      
      addEntities(scanner, entities);
      if (this.basePackages != null) {
	      for (String[] basePackages : this.basePackages) {
			 for (String basePackage : basePackages)
		     {
		        this.findEntities(scanner, entities, basePackage);
		     }
			 this.setAnnotatedClasses(entities
	            .toArray(new Class<?>[entities.size()]));
			 this.setAnnotatedPackages(basePackages);
	      }
      }
      super.afterPropertiesSet();
   }

   private ClassPathScanningCandidateComponentProvider createScanner()
   {
      ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false);
      scanner.addIncludeFilter( new AnnotationTypeFilter(Entity.class) );		
      scanner.addIncludeFilter(new AnnotationTypeFilter(Embeddable.class));
      return scanner;
   }

   private void findEntities(ClassPathScanningCandidateComponentProvider scanner, Collection<Class<?>> entities, String basePackage)
   {
      Set<BeanDefinition> annotatedClasses = scanner.findCandidateComponents(basePackage);
      
      for (BeanDefinition bd : annotatedClasses)
      {
         String className = bd.getBeanClassName();
         Class<?> type = ClassUtils.resolveClassName( className, this.beanClassLoader );
         entities.add( type );
      }
   }
   
   private void addEntities(ClassPathScanningCandidateComponentProvider scanner, Collection<Class<?>> entities)
   {
	   if(this.baseEntities != null){
		   for (String[] baseEntities : this.baseEntities) {
			 String className = "";
			 for (String baseEntity : baseEntities)
			 {
				 className = baseEntity;
			 }
	         Class<?> type = ClassUtils.resolveClassName( className, this.beanClassLoader );
	         entities.add( type );
	      }
	   }
   }
   
   
   /*-------------------------------------------------------------------
    *                       GET'S AND SET'S
    *-------------------------------------------------------------------*/
   public void setBasePackage(List<String[]> basePackage)
   {
	   this.basePackages = basePackage;     
      
   }  
   
   public void setBaseEntity(List<String[]> baseEntity)
   {
	   this.baseEntities = baseEntity;   
	   
	         
   }
   
   public void setBaseEntities(List<String[]> baseEntities)
   {
	   this.baseEntities = baseEntities;   
	   
	  
      
   }
   
   public void setBasePackages(List<String[]> basePackages)
   {
	   this.basePackages = basePackages;
   }
   
//   public void setBasePackageEssential(String basePackage)
//   {
//	    String[] basePackages = new String[]{ basePackage };     
//      
//        if( this.basePackages == null || this.basePackages.length<=0){
//		    this.basePackages = basePackages;
//	    }
//	  	else if(basePackages != null ){	  
//		  
//			String[] arrayTmp = new String[(basePackages.length + this.basePackages.length)];
//			
//			int i = 0;
//			for (String string : this.basePackages) {
//				arrayTmp[i] = string;
//				i++;
//			}
//			for (String string : basePackages) {
//				arrayTmp[i] = string;
//				i++;
//			}
//			
//			this.basePackages = arrayTmp;
//		
//	    }
//   }
//   public void setBasePackageEssentials(String[] basePackages)
//   {
//	    if( this.basePackages == null || this.basePackages.length<=0){
//		    this.basePackages = basePackages;
//	    }
//	  	else if(basePackages != null ){	  
//		  
//			String[] arrayTmp = new String[(basePackages.length + this.basePackages.length)];
//			
//			int i = 0;
//			for (String string : this.basePackages) {
//				arrayTmp[i] = string;
//				i++;
//			}
//			for (String string : basePackages) {
//				arrayTmp[i] = string;
//				i++;
//			}
//			
//			this.basePackages = arrayTmp;
//		
//	    }
//   }
   
   
  
   
   @Override
   public void setBeanClassLoader(ClassLoader beanClassLoader)
   {
	  
      this.beanClassLoader = beanClassLoader;
      super.setBeanClassLoader(beanClassLoader);
   }
}
